/*
 * Created on 15-Apr-2006 Actualis Center
 */
package org.bookie.framework.services.impl;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hivemind.ErrorHandler;
import org.apache.tapestry.IEngine;
import org.apache.tapestry.IExternalPage;
import org.apache.tapestry.IPage;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.engine.RequestCycle;
import org.apache.tapestry.engine.RequestCycleEnvironment;
import org.apache.tapestry.record.PropertyPersistenceStrategySource;
import org.apache.tapestry.services.AbsoluteURLBuilder;
import org.apache.tapestry.services.Infrastructure;
import org.apache.tapestry.services.ServiceConstants;
import org.apache.tapestry.util.QueryParameterMap;
import org.bookie.core.services.IMailSender;
import org.bookie.framework.services.EmailEngine;
import org.bookie.framework.services.EmailResponseRenderer;

/**
 * Default implementation of the {@link EmailEngine}
 * 
 * @author zubairov
 *
 */
public class EmailEngineImpl implements EmailEngine {

	private static final String MAIL_LIBRARY_NAMESPACE = "mail";

	private static final String EMAIL_SERVICE = "EmailService";

	private AbsoluteURLBuilder _absoluteURLBuilder;

	private EmailBaseEngine _emailBaseEngine = null;

	/**
	 * Delegate method for the servlet. Services the request.
	 */
	private RequestCycleEnvironment _environment;

	private ErrorHandler _errorHandler;

	/**
	 * The link to the world of HiveMind services.
	 */
	private Infrastructure _infrastructure;

	private final Log _logger = LogFactory.getLog(EmailEngineImpl.class);

	private EmailResponseRenderer _responseRenderer;

	private PropertyPersistenceStrategySource _strategySource;

	private IMailSender sender;
	
	/**
	 * Creates a new request cycle which is artificial one
	 * 
	 * @param pageName
	 * @param parameters
	 * @param engine
	 * @return
	 */
	private IRequestCycle createRequestCycle(String pageName,
			Object[] parameters, IEngine engine) {
		IRequestCycle cycle = null;
		Map<String, Object> parameterMap = new HashMap<String, Object>();
		parameterMap.put(ServiceConstants.PAGE, pageName);
		parameterMap.put(ServiceConstants.PARAMETER, parameters);

		QueryParameterMap _parameters = new QueryParameterMap(parameterMap);

		try {
			cycle = new RequestCycle(engine, _parameters, EMAIL_SERVICE,
					_environment);
		} catch (RuntimeException ex) {
			_logger.error("Error while sending email", ex);
		} catch (Exception ex) {
			_logger.error("Error while sending email", ex);
		}
		return cycle;
	}

	public void initializeService() {
		_environment = new RequestCycleEnvironment(_errorHandler,
				_infrastructure, _strategySource, _absoluteURLBuilder);
	}

	/**
	 * @param properties
	 * @param parameters
	 * @param html
	 * @param cycle
	 * @param page
	 */
	private void renderAndSendPage(String to, Object[] parameters,
			IRequestCycle cycle, IPage page) {
		try {

			cycle.setListenerParameters(parameters);

			cycle.activate(page);

			if (page instanceof IExternalPage) {
				IExternalPage extPage = (IExternalPage) page;
				extPage.activateExternalPage(parameters, cycle);
			}

			StringWriter writer = new StringWriter();
			PrintWriter pw = new PrintWriter(writer);
			_responseRenderer.setWriter(pw);

			_responseRenderer.renderResponse(cycle, true);
			String strContent = writer.toString();
			String subject = "Don't forget to specify title in the page";
			int start = strContent.indexOf("<title>");
			if (start >= 0) {
				int end = strContent.indexOf("</title>", start);
				if (end > start) {
					subject = strContent.substring(start + 7, end);
				}
			}
			sender.sendHTMLEmail(to, subject, strContent);

			return;
		} catch (Exception ex) {
			_logger.error("Error while rendering email", ex);
		} finally {

			try {
				cycle.cleanup();
				_infrastructure.getApplicationStateManager().flush();
			} catch (Exception ex) {
				_logger.error("Error during cleanup", ex);
			}
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void sendEmail(String to, String pageName, Object[] parameters) {
		IRequestCycle cycle = createRequestCycle(pageName, parameters,
				_emailBaseEngine);
		IPage page = cycle.getPage(MAIL_LIBRARY_NAMESPACE+":"+pageName);
		renderAndSendPage(to, parameters, cycle, page);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see actualis.web.tapestry.framework.EmailEngine#setAbsoluteURLBuilder(org.apache.tapestry.services.AbsoluteURLBuilder)
	 */
	public final void setAbsoluteURLBuilder(
			AbsoluteURLBuilder absoluteURLBuilder) {
		_absoluteURLBuilder = absoluteURLBuilder;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see actualis.web.tapestry.framework.EmailEngine#setEnvironment(org.apache.tapestry.engine.RequestCycleEnvironment)
	 */
	public final void setEnvironment(RequestCycleEnvironment environment) {
		_environment = environment;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see actualis.web.tapestry.framework.EmailEngine#setErrorHandler(org.apache.hivemind.ErrorHandler)
	 */
	public final void setErrorHandler(ErrorHandler errorHandler) {
		_errorHandler = errorHandler;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see actualis.web.tapestry.framework.EmailEngine#setInfrastructure(org.apache.tapestry.services.Infrastructure)
	 */
	public final void setInfrastructure(Infrastructure infrastructure) {
		_infrastructure = infrastructure;
		_emailBaseEngine = new EmailBaseEngine(infrastructure);
	}

	public final void setResponseRenderer(EmailResponseRenderer responseRenderer) {
		_responseRenderer = responseRenderer;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see actualis.web.tapestry.framework.EmailEngine#setStrategySource(org.apache.tapestry.record.PropertyPersistenceStrategySource)
	 */
	public final void setStrategySource(
			PropertyPersistenceStrategySource strategySource) {
		_strategySource = strategySource;
	}

	/**
	 * Injects MailSender service
	 * 
	 * @param sender
	 */
	public void setSender(IMailSender sender) {
		this.sender = sender;
	}
}
